/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.method;

import com.inspur.edp.caf.generator.baseInfo.ParameterInfo;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.caf.generator.method.ClassMethodGenerator;
import com.inspur.edp.caf.generator.utils.ExpressionUtils;
import com.inspur.edp.cef.api.message.CefException;
import com.inspur.edp.cef.designtime.api.IGspCommonDataType;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.element.GspElementObjectType;
import com.inspur.edp.cef.entity.accessor.base.IAccessor;
import com.inspur.edp.cef.entity.changeset.AddChangeDetail;
import com.inspur.edp.cef.entity.changeset.IChangeDetail;
import com.inspur.edp.cef.entity.changeset.ModifyChangeDetail;
import com.inspur.edp.cef.entity.entity.IEntityData;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.accessorgen.AccessorClassGenContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import com.inspur.edp.cef.generator.overall.GeneratorUtil;
import lombok.var;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.EnhancedForStatement;
import org.eclipse.jdt.core.dom.ExpressionStatement;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.NumberLiteral;
import org.eclipse.jdt.core.dom.ParameterizedType;
import org.eclipse.jdt.core.dom.ParenthesizedExpression;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SuperMethodInvocation;
import org.eclipse.jdt.core.dom.SwitchCase;
import org.eclipse.jdt.core.dom.SwitchStatement;
import org.eclipse.jdt.core.dom.ThrowStatement;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;

public class AccessorAcceptChangeGen extends ClassMethodGenerator {

    protected final String nodeCode;
    protected AccessorClassGenContext parentContext;
    protected  List<MediatePropertyInfo> dataType;
    protected static final String FormalParName = "change";
    private static String ParamVar = "var";
    private static String ParamPropertyChange = "propertyChange";

    public AccessorAcceptChangeGen(AccessorClassGenContext parentContext, String nodeCode,
        List<MediatePropertyInfo> dataType) {
        this.parentContext = parentContext;
        this.nodeCode = nodeCode;
        this.dataType = dataType;
    }

    @Override
    protected Block buildMethodBody() {
        addImport(IAccessor.class.getTypeName());
        Block block = ast.newBlock();
        addSuperStatement(block);
        addNewModifyChangeStatement(block);
        addJugeModifyNullStatement(block);
        addSetChangePropValuesStatement(block);
        addSetChangeChildsValuesStatement(ast, block);
        return block;
    }

    protected void addSuperStatement(Block block) {
        SuperMethodInvocation superInvocation = ast.newSuperMethodInvocation();
        superInvocation.setName(ast.newSimpleName(getMethodName()));
        superInvocation.arguments().add(ast.newSimpleName(FormalParName));
        block.statements().add(ast.newExpressionStatement(superInvocation));
    }

    //	ModifyChangeDetail val = change as ModifyChangeDetail;
    private void addNewModifyChangeStatement(Block block) {
        Object value = null;
        String change = value instanceof String ? (String) value : null;
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName(ParamVar));
        variableDeclarationFragment.setInitializer(ExpressionUtils
                .getAsExpression(ast, ast -> ast.newSimpleName(FormalParName),
                        ast -> new TypeInfo(ModifyChangeDetail.class).getType(ast)));

        VariableDeclarationStatement variableDeclarationStatement = ast
                .newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(
                new com.inspur.edp.caf.generator.baseInfo.TypeInfo(ModifyChangeDetail.class).getType(ast));

        block.statements().add(variableDeclarationStatement);
    }

    private void addJugeModifyNullStatement(Block block) {
        IfStatement ifStatement = ast.newIfStatement();

        InfixExpression infixExpression = ast.newInfixExpression();
        infixExpression.setOperator(InfixExpression.Operator.EQUALS);
        infixExpression.setLeftOperand(ast.newSimpleName(ParamVar));
        infixExpression.setRightOperand(ast.newNullLiteral());

        ifStatement.setExpression(infixExpression);

        Block blockStatement = ast.newBlock();
        ThrowStatement throwStatement = GeneratorUtil.getThrowStatement(ast,null);
        blockStatement.statements().add(throwStatement);
        addImport(CefException.class.getTypeName());
        ifStatement.setThenStatement(blockStatement);

        block.statements().add(ifStatement);
    }

    /*ModifyChangeDetail val =null;
      for(Map.Entry<String,Object>  propertyChange:val.getPropertyChanges().entrySet())
      {
        switch (propertyChange.getKey())
        {

        }
      }*/
    private void addSetChangePropValuesStatement(Block block) {
        EnhancedForStatement forStatement = ast.newEnhancedForStatement();
        addSetChangeProForParameter(forStatement);
        addSetChangeProForExpression(forStatement);
        addSetChangeProForBody(forStatement);
        block.statements().add(forStatement);
    }

    private void addSetChangeProForParameter(EnhancedForStatement forStatement) {
        SingleVariableDeclaration singleVariableDeclaration = ast.newSingleVariableDeclaration();
        singleVariableDeclaration.setName(ast.newSimpleName(ParamPropertyChange));
        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(
                ast.newQualifiedName(ast.newName(Map.class.getTypeName()), ast.newSimpleName("Entry"))));
        parameterizedType.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(String.class).getType(ast));
        parameterizedType.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(Object.class).getType(ast));
        singleVariableDeclaration.setType(parameterizedType);

        forStatement.setParameter(singleVariableDeclaration);
    }


    private void addSetChangeProForExpression(EnhancedForStatement forStatement) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("entrySet"));

        MethodInvocation methodInvocation1 = ast.newMethodInvocation();
        methodInvocation1.setName(ast.newSimpleName("getPropertyChanges"));
        methodInvocation1.setExpression(ast.newSimpleName(ParamVar));
        methodInvocation.setExpression(methodInvocation1);

        forStatement.setExpression(methodInvocation);
    }

    private void addSetChangeProForBody(EnhancedForStatement forStatement) {
        Block block = ast.newBlock();
        SwitchStatement switchStatement = ast.newSwitchStatement();
        addSetChangeProForSwitchExpression(switchStatement);
        addSetChangeProCases(switchStatement);
        block.statements().add(switchStatement);
        forStatement.setBody(block);
    }

    private void addSetChangeProForSwitchExpression(SwitchStatement switchStatement) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setExpression(ast.newSimpleName(ParamPropertyChange));
        methodInvocation.setName(ast.newSimpleName("getKey"));
        switchStatement.setExpression(methodInvocation);
    }

    private void addSetChangeProCases(SwitchStatement switchStatement) {
      for (MediatePropertyInfo field : dataType) {
          if(field.getElement() != null) {
              addSetChangeProCase(ast, nodeCode, field, switchStatement, parentContext);
          }
      }
    }

    public static void addSetChangeProCase(AST ast,String nodeCode, MediatePropertyInfo field,
                                           SwitchStatement switchStatement,
                                           AccessorClassGenContext parentContext) {
//        NestedConfigAtrribute nestedConfigAtrribute =
//                (NestedConfigAtrribute) ReflectionUtils
//                        .getMethodAnnotation(propertyInfo.getPropertyMethod(), NestedConfigAtrribute.class);

        SwitchCase switchCase = ast.newSwitchCase();
        StringLiteral stringLiteral = ast.newStringLiteral();
        stringLiteral.setLiteralValue(field.getElement().getLabelID());
        switchCase.setExpression(stringLiteral);
        switchStatement.statements().add(switchCase);

        if (field.getElement().getIsUdt()) {
            addNestedSetChangePropCase(ast,nodeCode, field.getElement(), switchStatement,parentContext);
            switchStatement.statements().add(ast.newBreakStatement());
            return;
        }
        else if(field.getElement().getObjectType()== GspElementObjectType.DynamicProp){
            addDynamicPropSetChangePropCase(ast, field.getElement(), switchStatement,parentContext);
            switchStatement.statements().add(ast.newBreakStatement());
            return;
        }
        //Java版临时注释：动态属性。
        else {
            addNormalSetChangePropCase(ast, field,nodeCode, switchStatement,parentContext);
            switchStatement.statements().add(ast.newBreakStatement());
            return;
        }
    }

    public static void addDynamicPropSetChangePropCase(
        AST ast,
        IGspCommonField field,
        SwitchStatement switchStatement,
        AccessorClassGenContext parentContext) {
      var thenBlock = ast.newBlock();
      var castStatement = ast.newCastExpression();
      castStatement.setType(
          new TypeInfo(IAccessor.class)
              .getType(ast, parentContext.getEntityDataGenContext().getProjContext()
                  .getCefGenContext().getCoreGenContext()));

      var getMethodExpression = ast.newMethodInvocation();
      getMethodExpression.setName(ast.newSimpleName("get"+field.getLabelID()));
      castStatement.setExpression(ast.newMethodInvocation());
      castStatement.setExpression(getMethodExpression);

      ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression();
      parenthesizedExpression.setExpression(castStatement);
      var acceptChangeExpression = ast.newMethodInvocation();
      acceptChangeExpression.setExpression(parenthesizedExpression);
      acceptChangeExpression.setName(ast.newSimpleName("acceptChange"));

      var argExpression = ast.newCastExpression();
      argExpression.setType(new TypeInfo(IChangeDetail.class)
          .getType(ast,
              parentContext.getEntityDataGenContext().getProjContext().getCefGenContext().getCoreGenContext()));
      argExpression.setExpression(
          ExpressionUtils.getMethodInvocation(ast, ParamPropertyChange, "getValue"));
      acceptChangeExpression.arguments().add(argExpression);

      thenBlock.statements().add(ast.newExpressionStatement(acceptChangeExpression));

      switchStatement.statements().add(thenBlock);
    }

    public static void addNestedSetChangePropCase(
            AST ast,
            String nodeCode,
            IGspCommonField field,
            SwitchStatement switchStatement,
            AccessorClassGenContext parentContext) {

        var ifStatement = ast.newIfStatement();
        // region condition
        var condition = ast.newInfixExpression();

        var leftExpression = ast.newCastExpression();
        leftExpression.setType(new TypeInfo(IChangeDetail.class)
                .getType(ast, parentContext.getEntityDataGenContext().getProjContext().getCefGenContext().getCoreGenContext()));
        leftExpression.setExpression(
                ExpressionUtils.getMethodInvocation(ast, ParamPropertyChange, "getValue"));
        condition.setLeftOperand(leftExpression);
        condition.setOperator(InfixExpression.Operator.NOT_EQUALS);
        condition.setRightOperand(ast.newNullLiteral());
        ifStatement.setExpression(condition);
        // endregion

        // region then
        var thenBlock = ast.newBlock();
        var castStatement = ast.newCastExpression();
        castStatement.setType(
                new TypeInfo(IAccessor.class)
                        .getType(ast,parentContext.getEntityDataGenContext().getProjContext().getCefGenContext().getCoreGenContext()));

        var getMethodExpression = ast.newMethodInvocation();
        getMethodExpression.setName(ast.newSimpleName("get"+field.getLabelID()));
        castStatement.setExpression(ast.newMethodInvocation());
        castStatement.setExpression(getMethodExpression);

        ParenthesizedExpression parenthesizedExpression=ast.newParenthesizedExpression();
        parenthesizedExpression.setExpression(castStatement);
        var acceptChangeExpression = ast.newMethodInvocation();
        acceptChangeExpression.setExpression(parenthesizedExpression);
        acceptChangeExpression.setName(ast.newSimpleName("acceptChange"));

        var argExpression = ast.newCastExpression();
        argExpression.setType(new TypeInfo(IChangeDetail.class)
                .getType(ast, parentContext.getEntityDataGenContext().getProjContext().getCefGenContext().getCoreGenContext()));
        argExpression.setExpression(
                ExpressionUtils.getMethodInvocation(ast, ParamPropertyChange, "getValue"));
        acceptChangeExpression.arguments().add(argExpression);

        thenBlock.statements().add(ast.newExpressionStatement(acceptChangeExpression));
        ifStatement.setThenStatement(thenBlock);
        // endregion

        // region else

        var elseBlock =ast.newBlock();
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("set"+field.getLabelID()));

        CastExpression castExpression = ast.newCastExpression();
        castExpression.setType(parentContext.getEntityDataGenContext().getFieldTypeInfo(nodeCode,field).getType(ast));
        MethodInvocation methodInvocation1 = ast.newMethodInvocation();
        methodInvocation1.setName(ast.newSimpleName("getValue"));
        methodInvocation1.setExpression(ast.newSimpleName(ParamPropertyChange));
        castExpression.setExpression(methodInvocation1);

        methodInvocation.arguments().add(castExpression);
        elseBlock.statements().add(ast.newExpressionStatement(methodInvocation));


//        var reinitializeUdtAccessor = new List<StatementSyntax>();
//        AccessorInitializeNestedGen.addNestedInitializer(parentContext, reinitializeUdtAccessor, prop,
//                prop.GetCustomAttribute<NestedConfigAtrribute>());

        //endregion


        switchStatement.statements().add(ifStatement);

    }

    public static void addNormalSetChangePropCase(AST ast, MediatePropertyInfo field,String nodeCode,
                                                  SwitchStatement switchStatement,AccessorClassGenContext parentContext) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("set"+field.getElement().getLabelID()));

        CastExpression castExpression = ast.newCastExpression();
        TypeInfo info=field.getPropertyType();
        castExpression.setType( info.getType(ast,parentContext.getEntityDataGenContext().getProjContext().getCefGenContext().getCoreGenContext()));
        MethodInvocation methodInvocation1 = ast.newMethodInvocation();
        methodInvocation1.setName(ast.newSimpleName("getValue"));
        methodInvocation1.setExpression(ast.newSimpleName(ParamPropertyChange));
        castExpression.setExpression(methodInvocation1);

        methodInvocation.arguments().add(castExpression);

        ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
        switchStatement.statements().add(expressionStatement);
    }

    public static void addSetChangeChildsValuesStatement(AST ast, Block block) {
        IfStatement ifStatement = ast.newIfStatement();
        addSetChangeChildsValuesIfExpression(ast, ifStatement);
        addSetChangeChildsValuesIfThen(ast, ifStatement);
        block.statements().add(ifStatement);
    }

    private static void addSetChangeChildsValuesIfThen(AST ast, IfStatement ifStatement) {
        Block block = ast.newBlock();
        addSetChangeChildsValuesThenFor(ast, block);
        ifStatement.setThenStatement(block);
    }

    private static void addSetChangeChildsValuesThenFor(AST ast, Block block) {
        EnhancedForStatement forStatement = ast.newEnhancedForStatement();
        addSetChangeChildsValuesIfThenForParameter(ast, forStatement);
        addSetChangeChildsValuesIfThenForExpression(ast, forStatement);
        addSetChangeChildsValuesIfThenForBody(ast, forStatement);
        block.statements().add(forStatement);
    }

    private static void addSetChangeChildsValuesIfThenForParameter(AST ast,EnhancedForStatement forStatement) {
        SingleVariableDeclaration singleVariableDeclaration = ast.newSingleVariableDeclaration();

        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(
                ast.newQualifiedName(ast.newName(Map.class.getTypeName()), ast.newSimpleName("Entry"))));
        parameterizedType.typeArguments().add(new TypeInfo(String.class).getType(ast));

        ParameterizedType parameterizedTypeInner = ast.newParameterizedType(
                new com.inspur.edp.caf.generator.baseInfo.TypeInfo(Map.class).getType(ast));
        parameterizedTypeInner.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(String.class).getType(ast));
        parameterizedTypeInner.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(IChangeDetail.class).getType(ast));

        parameterizedType.typeArguments().add(parameterizedTypeInner);

        singleVariableDeclaration.setType(parameterizedType);
        singleVariableDeclaration.setName(ast.newSimpleName("childChange"));

        forStatement.setParameter(singleVariableDeclaration);
    }

    private static void addSetChangeChildsValuesIfThenForExpression(AST ast, EnhancedForStatement forStatement) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();
        methodInvocation.setName(ast.newSimpleName("entrySet"));

        MethodInvocation methodInvocationExpression = ast.newMethodInvocation();
        methodInvocationExpression.setExpression(ast.newSimpleName(ParamVar));
        methodInvocationExpression.setName(ast.newSimpleName("getChildChanges"));

        methodInvocation.setExpression(methodInvocationExpression);

        forStatement.setExpression(methodInvocation);
    }

    private static void addSetChangeChildsValuesIfThenForBody(AST ast, EnhancedForStatement forStatement) {
        Block block = ast.newBlock();
        EnhancedForStatement forStatementChangeItem = ast.newEnhancedForStatement();
        addSetChangeChildInnerForStatementParameter(ast, forStatementChangeItem);
        addSetChangeChildInnerForStatementExpression(ast, forStatementChangeItem);
        addSetChangeChildInnerForStatementBody(ast, forStatementChangeItem);
        block.statements().add(forStatementChangeItem);
        forStatement.setBody(block);
    }

    private static void addSetChangeChildInnerForStatementParameter(AST ast,
            EnhancedForStatement forStatementChangeItem) {
        SingleVariableDeclaration singleVariableDeclaration = ast.newSingleVariableDeclaration();

        ParameterizedType parameterizedType = ast.newParameterizedType(ast.newSimpleType(
                ast.newQualifiedName(ast.newName(Map.class.getTypeName()), ast.newSimpleName("Entry"))));
        parameterizedType.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(String.class).getType(ast));
        parameterizedType.typeArguments()
                .add(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(IChangeDetail.class).getType(ast));

        singleVariableDeclaration.setType(parameterizedType);
        singleVariableDeclaration.setName(ast.newSimpleName("item"));

        forStatementChangeItem.setParameter(singleVariableDeclaration);
    }

    private static void addSetChangeChildInnerForStatementExpression(
        AST ast,EnhancedForStatement forStatementChangeItem) {
        MethodInvocation methodInvocation = ast.newMethodInvocation();

        MethodInvocation methodInvocationExpression = ast.newMethodInvocation();
        methodInvocationExpression.setExpression(ast.newSimpleName("childChange"));
        methodInvocationExpression.setName(ast.newSimpleName("getValue"));
        methodInvocation.setExpression(methodInvocationExpression);
        methodInvocation.setName(ast.newSimpleName("entrySet"));
        forStatementChangeItem.setExpression(methodInvocation);
    }

    private static void addSetChangeChildInnerForStatementBody(AST ast, EnhancedForStatement forStatementChangeItem) {
        Block block = ast.newBlock();
        addNewAddChangeStatement(ast, block);
        addSetChangeValueIfStatement(ast, block);
        forStatementChangeItem.setBody(block);
    }

    private static void addNewAddChangeStatement(AST ast, Block block) {
        VariableDeclarationFragment variableDeclarationFragment = ast.newVariableDeclarationFragment();
        variableDeclarationFragment.setName(ast.newSimpleName("val2"));

        variableDeclarationFragment.setInitializer(ExpressionUtils.getAsExpression(ast, providerAst -> {
            MethodInvocation methodInvocation = providerAst.newMethodInvocation();
            methodInvocation.setExpression(providerAst.newSimpleName("item"));
            methodInvocation.setName(providerAst.newSimpleName("getValue"));
            return methodInvocation;
        }, providerAst -> new com.inspur.edp.caf.generator.baseInfo.TypeInfo(AddChangeDetail.class)
                .getType(providerAst)));

        VariableDeclarationStatement variableDeclarationStatement = ast
                .newVariableDeclarationStatement(variableDeclarationFragment);
        variableDeclarationStatement.setType(
                new com.inspur.edp.caf.generator.baseInfo.TypeInfo(AddChangeDetail.class).getType(ast));
        block.statements().add(variableDeclarationStatement);
    }

    private static void addSetChangeValueIfStatement(AST ast,Block block) {
        IfStatement ifStatement = ast.newIfStatement();
        addSetChangeValueIfExpression(ast, ifStatement);
        addSetChangeValueIfThen(ast, ifStatement);
        addSetChangeValueIfElse(ast, ifStatement);
        block.statements().add(ifStatement);
    }

    private static void addSetChangeValueIfExpression(AST ast,IfStatement ifStatement) {
        InfixExpression infixExpression = ast.newInfixExpression();
        infixExpression.setLeftOperand(ast.newSimpleName("val2"));
        infixExpression.setOperator(InfixExpression.Operator.NOT_EQUALS);
        infixExpression.setRightOperand(ast.newNullLiteral());

        ifStatement.setExpression(infixExpression);
    }

    private static void addSetChangeValueIfThen(AST ast,IfStatement ifStatement) {
        Block block = ast.newBlock();

        MethodInvocation methodInvocation = ast.newMethodInvocation();
        addSetChangeValueIfExpressionMethoInvokeExpression(ast, methodInvocation);
        methodInvocation.setName(ast.newSimpleName("add"));
        addSetChangeValueIfExpressionMethoInvokeArguments(ast, methodInvocation);
        ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
        block.statements().add(expressionStatement);

        ifStatement.setThenStatement(block);
    }

    private static void addSetChangeValueIfExpressionMethoInvokeExpression(AST ast,
            MethodInvocation methodInvocation) {
        MethodInvocation methodInvocationExpression = ast.newMethodInvocation();

        MethodInvocation getChildsInvocation = ast.newMethodInvocation();
        getChildsInvocation.setName(ast.newSimpleName("getChilds"));
        methodInvocationExpression.setExpression(getChildsInvocation);
        methodInvocationExpression.setName(ast.newSimpleName("get"));

        MethodInvocation methodInvocationGetKey = ast.newMethodInvocation();
        methodInvocationGetKey.setExpression(ast.newSimpleName("childChange"));
        methodInvocationGetKey.setName(ast.newSimpleName("getKey"));

        methodInvocationExpression.arguments().add(methodInvocationGetKey);
        methodInvocation.setExpression(methodInvocationExpression);
    }

    private static void addSetChangeValueIfExpressionMethoInvokeArguments(
            AST ast,MethodInvocation methodInvocation) {
        CastExpression castExpression = ast.newCastExpression();
        castExpression.setType(
                new com.inspur.edp.caf.generator.baseInfo.TypeInfo(IEntityData.class).getType(ast));

        MethodInvocation methodInvocationCopy = ast.newMethodInvocation();
        methodInvocationCopy.setName(ast.newSimpleName("copy"));

        MethodInvocation methodInvocationExpression = ast.newMethodInvocation();

        methodInvocationExpression.setName(ast.newSimpleName("getEntityData"));
        methodInvocationExpression.setExpression(ast.newSimpleName("val2"));
        methodInvocationCopy.setExpression(methodInvocationExpression);
        castExpression.setExpression(methodInvocationCopy);
        methodInvocation.arguments().add(castExpression);
    }

    private static void addSetChangeValueIfElse(AST ast,IfStatement ifStatement) {
        Block block = ast.newBlock();
        MethodInvocation methodInvocationElse = ast.newMethodInvocation();
        addSetMethodInvokeElseExpression(ast, methodInvocationElse);
        methodInvocationElse.setName(ast.newSimpleName("acceptChange"));
        addSetMethodInvokeElseArgument(ast, methodInvocationElse);
        ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocationElse);
        block.statements().add(expressionStatement);
        ifStatement.setElseStatement(block);
    }

    private static void addSetMethodInvokeElseExpression(AST ast,MethodInvocation methodInvocationElse) {
        ParenthesizedExpression parenthesizedExpression = ast.newParenthesizedExpression();
        CastExpression castExpression = ast.newCastExpression();
        castExpression
                .setType(new com.inspur.edp.caf.generator.baseInfo.TypeInfo(IAccessor.class).getType(ast));

        MethodInvocation methodInvocationGetItem = ast.newMethodInvocation();
        methodInvocationGetItem.setName(ast.newSimpleName("getItem"));

        addgetitemExpression(ast, methodInvocationGetItem);
        addgetitemArguments(ast, methodInvocationGetItem);
        castExpression.setExpression(methodInvocationGetItem);

        parenthesizedExpression.setExpression(castExpression);

        methodInvocationElse.setExpression(parenthesizedExpression);
    }

    private static void addgetitemExpression(AST ast,MethodInvocation methodInvocationGetItem) {
        MethodInvocation methodInvocation1 = ast.newMethodInvocation();
        methodInvocation1.setName(ast.newSimpleName("getChilds"));

        MethodInvocation methodInvocationGet = ast.newMethodInvocation();
        methodInvocationGet.setExpression(methodInvocation1);
        methodInvocationGet.setName(ast.newSimpleName("get"));

        MethodInvocation methodInvocationGetKey = ast.newMethodInvocation();
        methodInvocationGetKey.setName(ast.newSimpleName("getKey"));
        methodInvocationGetKey.setExpression(ast.newSimpleName("childChange"));

        methodInvocationGet.arguments().add(methodInvocationGetKey);
        methodInvocationGetItem.setExpression(methodInvocationGet);
    }

    private static void addgetitemArguments(AST ast,MethodInvocation methodInvocationGetItem) {
        MethodInvocation methodInvocation1 = ast.newMethodInvocation();
        methodInvocation1.setExpression(ast.newSimpleName("item"));
        methodInvocation1.setName(ast.newSimpleName("getKey"));
        methodInvocationGetItem.arguments().add(methodInvocation1);
    }

    private static void addSetMethodInvokeElseArgument(AST ast,MethodInvocation methodInvocationElse) {
        MethodInvocation methodInvocation1 = ast.newMethodInvocation();

        methodInvocation1.setExpression(ast.newSimpleName("item"));
        methodInvocation1.setName(ast.newSimpleName("getValue"));

        methodInvocationElse.arguments().add(methodInvocation1);
    }

    private static void addSetChangeChildsValuesIfExpression(AST ast, IfStatement ifStatement) {
        InfixExpression infixExpression = ast.newInfixExpression();
        MethodInvocation getChildChangeInvocation = ast.newMethodInvocation();
        getChildChangeInvocation.setName(ast.newSimpleName("getChildChanges"));
        getChildChangeInvocation.setExpression(ast.newSimpleName(ParamVar));
        MethodInvocation getSizeInvocation = ast.newMethodInvocation();
        getSizeInvocation.setName(ast.newSimpleName("size"));
        getSizeInvocation.setExpression(getChildChangeInvocation);
        infixExpression.setLeftOperand(getSizeInvocation);
        infixExpression.setOperator(InfixExpression.Operator.GREATER);
        NumberLiteral numberLiteral = ast.newNumberLiteral();
        numberLiteral.setToken("0");
        infixExpression.setRightOperand(numberLiteral);
        ifStatement.setExpression(infixExpression);
    }

    @Override
    protected String getMethodName() {
        return "acceptChangeCore";
    }

    @Override
    protected TypeInfo getReturnType() {
        return new TypeInfo(void.class.getTypeName());
    }

    @Override
    protected boolean getIsOverride() {
        return true;
    }

    @Override
    protected ArrayList<Modifier.ModifierKeyword> getAccessModifiers() {
        ArrayList<Modifier.ModifierKeyword> list = new ArrayList<>();
        list.add(Modifier.ModifierKeyword.PROTECTED_KEYWORD);
        return list;
    }

    @Override
    protected ArrayList<ParameterInfo> getParameterCollection() {
        ArrayList<ParameterInfo> list = new ArrayList<>();
        ParameterInfo parameterInfo = new ParameterInfo();
        parameterInfo.setParamName(FormalParName);
        parameterInfo.setParamType(new TypeInfo(IChangeDetail.class.getTypeName()));
        list.add(parameterInfo);
        return list;
    }
}
